package me.project.jobster.common.util;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * Class BeanUtils
 *
 * @author jacksonzzy
 * @version $Revision:0.1
 */
public class BeanUtils extends org.apache.commons.beanutils.BeanUtils {

    private static void convert(Object dest, Object orig) throws
            IllegalAccessException, InvocationTargetException {

        // Validate existence of the specified beans
        if (dest == null) {
            throw new IllegalArgumentException
                    ("No destination bean specified");
        }
        if (orig == null) {
            throw new IllegalArgumentException("No origin bean specified");
        }

        // Copy the properties, converting as necessary
        if (orig instanceof DynaBean) {
            DynaProperty origDescriptors[] =
                    ((DynaBean) orig).getDynaClass().getDynaProperties();
            for (DynaProperty origDescriptor : origDescriptors) {
                String name = origDescriptor.getName();
                if (PropertyUtils.isWriteable(dest, name)) {
                    Object value = ((DynaBean) orig).get(name);
                    try {
                        copyProperty(dest, name, value);
                    } catch (Exception e) {
                        ; // Should not happen
                    }

                }
            }
        } else if (orig instanceof Map) {
            for (Object o : ((Map) orig).keySet()) {
                String name = (String) o;
                if (PropertyUtils.isWriteable(dest, name)) {
                    Object value = ((Map) orig).get(name);
                    try {
                        copyProperty(dest, name, value);
                    } catch (Exception e) {
                        ; // Should not happen
                    }

                }
            }
        } else
            /* if (orig is a standard JavaBean) */ {
            PropertyDescriptor origDescriptors[] =
                    PropertyUtils.getPropertyDescriptors(orig);
            for (PropertyDescriptor origDescriptor : origDescriptors) {
                String name = origDescriptor.getName();
                if ("class".equals(name)) {
                    continue; // No point in trying to set an object's class
                }
                if (PropertyUtils.isReadable(orig, name) &&
                        PropertyUtils.isWriteable(dest, name)) {
                    try {
                        Object value = PropertyUtils.getSimpleProperty(orig, name);
                        copyProperty(dest, name, value);
                    } catch (IllegalArgumentException ie) {
                        ; // Should not happen
                    } catch (Exception e) {
                        ; // Should not happen
                    }

                }
            }
        }

    }


    /**
     * 对象拷贝
     * 数据对象空值不拷贝到目标对象
     *
     * @param dataObject
     * @param toObject
     * @throws NoSuchMethodException copy
     */
    public static void copyBeanNotNull2Bean(Object databean, Object tobean) throws Exception {
        PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(databean);
        for (PropertyDescriptor origDescriptor : origDescriptors) {
            String name = origDescriptor.getName();
            if ("class".equals(name)) {
                continue; // No point in trying to set an object's class
            }
            if (PropertyUtils.isReadable(databean, name) && PropertyUtils.isWriteable(tobean, name)) {
                try {
                    Object value = PropertyUtils.getSimpleProperty(databean, name);
                    if (value != null) {
                        copyProperty(tobean, name, value);
                    }
                } catch (Exception e) {
                    ; // Should not happen
                }

            }
        }
    }


    /**
     * 把orig和dest相同属性的value复制到dest中
     *
     * @param dest
     * @param orig
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static void copyBean2Bean(Object dest, Object orig) throws Exception {
        convert(dest, orig);
    }

    /**
     * @param @param targetClass 目标对象类名
     * @param @param orig   源bean
     * @return void
     * @Title: copyBean
     * @Description: TODO 拷贝对象相同属性到另一个对象
     * @date 2016年5月10日
     * @author yy
     */
    public static <T> T copyBean(Class<T> targetClass, Object orig) {
        if (orig == null)
            return null;
        try {
            T obj = targetClass.newInstance();
            convert(obj, orig);
            return obj;
        } catch (Exception e) {
            throw new RuntimeException("copy bean 出现错误，", e);
        }
    }

    public static void copyBean2Map(Map<String, Object> map, Object bean) {
        PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(bean);
        for (PropertyDescriptor pd : pds) {
            String propname = pd.getName();
            try {
                Object propvalue = PropertyUtils.getSimpleProperty(bean, propname);
                if (!StringUtils.equalsIgnoreCase(propname, "class")) {
                    map.put(propname, propvalue);
                }
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                //e.printStackTrace();
            }
        }
    }

    /**
     * 将Map内的key与Bean中属性相同的内容复制到BEAN中
     *
     * @param bean       Object
     * @param properties Map
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static void copyMap2Bean(Object bean, Map<String, Object> properties) throws
            IllegalAccessException, InvocationTargetException {
        // Do nothing unless both arguments have been specified
        if ((bean == null) || (properties == null)) {
            return;
        }
        // Loop through the property name/value pairs to be set
        for (String name : properties.keySet()) {
            // Identify the property name and value(s) to be assigned
            if (name == null) {
                continue;
            }
            Object value = properties.get(name);
            try {
                Class clazz = PropertyUtils.getPropertyType(bean, name);
                if (null == clazz) {
                    continue;
                }
                String className = clazz.getName();
                if (className.equalsIgnoreCase("java.sql.Timestamp")) {
                    if (value == null || value.equals("")) {
                        continue;
                    }
                }
                setProperty(bean, name, value);
            } catch (NoSuchMethodException ignored) {
            }
        }
    }


    /**
     * 自动转Map key值大写
     * 将Map内的key与Bean中属性相同的内容复制到BEAN中
     *
     * @param bean       Object
     * @param properties Map
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static void copyMap2Bean_Nobig(Object bean, Map<String, Object> properties) throws
            IllegalAccessException, InvocationTargetException {
        // Do nothing unless both arguments have been specified
        if ((bean == null) || (properties == null)) {
            return;
        }
        // Loop through the property name/value pairs to be set
        Iterator<String> names = properties.keySet().iterator();
        while (names.hasNext()) {
            String name = names.next();
            // Identify the property name and value(s) to be assigned
            if (name == null) {
                continue;
            }
            Object value = properties.get(name);
            // 命名应该大小写应该敏感(否则取不到对象的属性)
            try {
                if (value == null) {
                    // 不光Date类型，好多类型在null时会出错
                    // 如果为null不用设 (对象如果有特殊初始值也可以保留？)
                    continue;
                }
                Class clazz = PropertyUtils.getPropertyType(bean, name);
                if (null == clazz) {
                    // 在bean中这个属性不存在
                    continue;
                }
                String className = clazz.getName();
                // 临时对策（如果不处理默认的类型转换时会出错）
                if (className.equalsIgnoreCase("java.util.Date")) {
                    // wait to do：貌似有时区问题, 待进一步确认
                    value = new java.util.Date(((java.sql.Timestamp) value).getTime());
                }
                setProperty(bean, name, value);
            } catch (NoSuchMethodException ignored) {
            }
        }
    }

    /**
     * Map内的key与Bean中属性相同的内容复制到BEAN中
     * 对于存在空值的取默认值
     *
     * @param bean         Object
     * @param properties   Map
     * @param defaultValue String
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static void copyMap2Bean(Object bean, Map<String, Object> properties, String defaultValue) throws
            IllegalAccessException, InvocationTargetException {
        // Do nothing unless both arguments have been specified
        if ((bean == null) || (properties == null)) {
            return;
        }
        // Loop through the property name/value pairs to be set
        for (String name : properties.keySet()) {
            // Identify the property name and value(s) to be assigned
            if (name == null) {
                continue;
            }
            Object value = properties.get(name);
            try {
                Class clazz = PropertyUtils.getPropertyType(bean, name);
                if (null == clazz) {
                    continue;
                }
                String className = clazz.getName();
                if ("java.sql.Timestamp".equalsIgnoreCase(className)) {
                    if (value == null || value.equals("")) {
                        continue;
                    }
                }
                if ("java.lang.String".equalsIgnoreCase(className)) {
                    if (value == null) {
                        value = defaultValue;
                    }
                }
                setProperty(bean, name, value);
            } catch (NoSuchMethodException ignored) {
            }
        }
    }

    /**
     * 将List<Map> 装换为 List<Bean>
     *
     * @param <T>
     * @param targetClass 目标对象的类,必须有public 的 无参数的 construct method.
     * @param sources     数据源
     * @return 数据目标
     */
    public static <T> List<? extends T> copyMapToBeanList(Class<T> targetClass, List sources) {
        if (sources == null || sources.isEmpty()) {
            return null;
        }
        List<T> returnlist = new ArrayList<T>();
        try {
            for (Object sourceObject : sources) {
                T bean = targetClass.newInstance();
                copyMap2Bean(bean, (Map<String, Object>) sourceObject);
                returnlist.add(bean);
            }
            return returnlist;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public BeanUtils() {
        super();
    }
}